home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / mm / ccmd / stdact.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-12-18  |  39.0 KB  |  1,583 lines

  1. /*
  2.  Copyright (c) 1986, 1990 by The Trustees of Columbia University in
  3.  the City of New York.  Permission is granted to any individual or
  4.  institution to use, copy, or redistribute this software so long as it
  5.  is not sold for profit, provided this copyright notice is retained.
  6.  
  7.  Author: Andrew Lowry ; Major Modifications: Howie Kaye
  8. */
  9. /* stdact 
  10. ** 
  11. ** Standard command action routines.  These actions are modeled after 
  12. ** those found in the TOPS-20 COMND jsys.  The standard actions defined 
  13. ** here will be used unless the programmer specifically provides an 
  14. ** overriding set of actions.  
  15. **/
  16.  
  17. /*
  18.  * these routines were all static.  They are often useful inside applications
  19.  * though, so...they are no longer static
  20.  */
  21.  
  22. #include "ccmdlib.h"        /* get ccmd package user symbols */
  23. #include "cmfncs.h"        /* and internal symbols */
  24.  
  25. /* Calling conventions for action routines:
  26. **
  27. ** Input arguments:
  28. **   fdblist - A pointer to the list of FDB's for this field.
  29. **   brk - The break character that caused this action.
  30. **   deferred - TRUE if this action is invoked in deferred mode (ie, the
  31. **     current input resulted in an incomplete parse) or immediate mode
  32. **     (immediately after the action character was typed).
  33. **
  34. ** Output arguments: None.
  35. ** Returns: Standard return code.  CMxDFR will cause the action to be
  36. **   invoked again later in deferred mode, as soon as some field results
  37. **   in an incomplete parse.  CMxRPT will cause a reparse.  CMxGO will
  38. **   cause a wakeup following the action, and CMxOK will indicate a
  39. **   successful action without a subsequent wakeup.
  40. **/
  41.  
  42. /* Forward declarations for auxilliary routines */
  43. int *goto_end_of_line(), *goto_beginning_of_line(), goto_current_pos(),
  44.     *go_forward_char(), *go_backward_char();
  45.  
  46. /* Forward declarations for action routines */
  47. int cmpact(), cmpact2(), pcmact(), hlpact(), cfmact(), delact();
  48. int begact(), wrdact(), fixact(), hstact(), bsact(), quoact();
  49. int indiract(), prevact(), nextact();
  50.  
  51. int begline(), endline(), backchar(), forchar(), delchar();
  52. int killeol(), twiddle(), cmprefix(), killword(), backword(), forword();
  53. int cmp_pre();
  54. #ifdef TIOCSUST
  55. int loadav(), twiddle_or_load();
  56. #endif /* TIOCSUST */
  57.  
  58. int pbeep();
  59. int bupcase_word(), bdowncase_word(), bcap_word();
  60. int fupcase_word(), fdowncase_word(), fcap_word();
  61. int upcase_word(), downcase_word(), cap_word();
  62.  
  63.  
  64. static cmacttab gmacs_actions[] = {
  65.     { '\001', begline },        /* ^A beginning of line */
  66.     { '\002', backchar },        /* ^B backwards character */
  67.     { '\004', delchar },        /* ^D delete character */
  68.     { '\005', endline },        /* ^E end of line */
  69.     { '\006', forchar },        /* ^F forward character */
  70.     { '\010', bsact },            /* ^H backspace or history */
  71.     { '\011', cmpact2 },        /* TAB - completion */
  72.     { '\012', cfmact },            /* ^J confirm */
  73.     { '\013', killeol },        /* ^K - kill to end of line */
  74.     { '\014', cfmact },            /* ^L - confirm */
  75.     { '\015', cfmact },            /* ^M - confirm */
  76.     { '\016', nextact },        /* ^N - next line (history) */
  77.     { '\020', prevact },        /* ^P - previous line (history) */
  78.     { '\022', fixact },            /* ^R - redisplay line */
  79. #ifdef TIOCSUST
  80.     { '\024', twiddle_or_load },    /* ^T twiddle chars or disp loadav */
  81. #else
  82.     { '\024', twiddle },        /* ^T twiddle chars */
  83. #endif
  84.     { '\025', begact },            /* ^U - erase line */
  85.     { '\026', quoact },            /* ^V - quote next char */
  86.     { '\027', wrdact },            /* ^W delete backwards word */
  87.     { '\033', cmprefix },        /* ESC - prefix char */
  88.     { '@',    indiract },        /* @ - indirect file */
  89.     { '?',    hlpact },            /* ? - help */
  90.     { '\177', delact },            /* ^? delete backward char */
  91.     { '\000', NULL },            /* end of table */
  92. };
  93.  
  94. static cmacttab emacs_actions[] = {
  95.     { '\001', begline },        /* ^A beginning of line */
  96.     { '\002', backchar },        /* ^B backwards character */
  97.     { '\004', delchar },        /* ^D delete character */
  98.     { '\005', endline },        /* ^E end of line */
  99.     { '\006', forchar },        /* ^F forward character */
  100.     { '\010', bsact },            /* ^H backspace or history */
  101.     { '\011', cmpact2 },        /* TAB - completion */
  102.     { '\012', cfmact },            /* ^J confirm */
  103.     { '\013', killeol },        /* ^K - kill to end of line */
  104.     { '\014', cfmact },            /* ^L - confirm */
  105.     { '\015', cfmact },            /* ^M - confirm */
  106.     { '\016', nextact },        /* ^N - next line (history) */
  107.     { '\020', prevact },        /* ^P - previous line (history) */
  108.     { '\022', fixact },            /* ^R - redisplay line */
  109. #ifdef TIOCSUST
  110.     { '\024', twiddle_or_load },    /* ^T twiddle chars or disp loadav */
  111. #else
  112.     { '\024', twiddle },        /* ^T twiddle chars */
  113. #endif
  114.     { '\025', begact },            /* ^U - erase line */
  115.     { '\026', quoact },            /* ^V - quote next char */
  116.     { '\027', wrdact },            /* ^W delete backwards word */
  117.     { '\033', cmp_pre },        /* ESC - completion and prefix char */
  118.     { '@',    indiract },        /* @ - indirect file */
  119.     { '?',    hlpact },            /* ? - help */
  120.     { '\177', delact },            /* ^? delete backward char */
  121.     { '\000', NULL },            /* end of table */
  122. };
  123.  
  124.  
  125. static cmacttab emacs_prefix_actions[] = {
  126.     { '\011', cmpact2 },        /* M-TAB - completion */
  127.     { '\033', cmpact },            /* M-ESC - completion */
  128.     { 'b', backword },            /* M-b - backwards word */
  129.     { 'c', cap_word },            /* M-c capitalize word */
  130.     { 'd', killword },            /* M-d delete forwards word */
  131.     { 'f', forword },            /* M-f move forwards word */
  132.     { 'l', downcase_word },        /* M-l downcase word */
  133.     { 'u', upcase_word },        /* M-u upcase word */
  134.     { 'B', backword },            /* M-B - backwards word */
  135.     { 'C', cap_word },            /* M-C capitalize word */
  136.     { 'D', killword },            /* M-D delete forwards word */
  137.     { 'F', forword },            /* M-F move forwards word */
  138.     { 'L', downcase_word },        /* M-L downcase word */
  139.     { 'U', upcase_word },        /* M-U upcase word */
  140.     { '\0', NULL },
  141. };
  142.  
  143. static int forward_casing = TRUE;    /* case changes go forwards */
  144. static int ignore_eof = TRUE;        /* ignore ^D's */
  145.  
  146.  
  147. #define NCHAR 128            /* size of action tables */
  148.  
  149. /* Standard action table with defaults loaded */
  150. int (*(stdact[NCHAR]))() = {
  151.     NULL,   begline,   backchar,NULL,      delchar,endline,forchar, NULL,
  152.     bsact,  cmpact2,   cfmact, killeol,   cfmact, cfmact, nextact, NULL,
  153.     prevact,   NULL,   fixact, NULL,   
  154. #ifdef TIOCSUST
  155.                         twiddle_or_load,
  156. #else
  157.                         twiddle,
  158. #endif /* TIOCSUST */
  159.                         begact, quoact, wrdact,
  160.     NULL,   NULL,   NULL,   cmp_pre, NULL,   NULL,   NULL,   NULL,
  161.     NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
  162.     NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
  163.     NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
  164.     NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   hlpact,
  165.     indiract,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
  166.     NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
  167.     NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
  168.     NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
  169.     NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
  170.     NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
  171.     NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
  172.     NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   delact
  173. };
  174.  
  175. int (*(preact[NCHAR]))() = {
  176.     pbeep,   pbeep,   pbeep,   pbeep,   pbeep,   pbeep,   pbeep,   pbeep,   
  177.     pbeep,   pbeep,   pbeep,   pbeep,   pbeep,   pbeep,   pbeep,   pbeep,   
  178.     pbeep,   pbeep,   pbeep,   pbeep,   pbeep,   pbeep,   pbeep,   pbeep,   
  179.     pbeep,   pbeep,   pbeep,   cmpact,   pbeep,   pbeep,   pbeep,   pbeep,
  180.     pbeep,   pbeep,   pbeep,   pbeep,   pbeep,   pbeep,   pbeep,   pbeep,   
  181.     pbeep,   pbeep,   pbeep,   pbeep,   pbeep,   pbeep,   pbeep,   pbeep,   
  182.     pbeep,   pbeep,   pbeep,   pbeep,   pbeep,   pbeep,   pbeep,   pbeep,   
  183.     pbeep,   pbeep,   pbeep,   pbeep,   pbeep,   pbeep,   pbeep,   pbeep,   
  184.     pbeep,   pbeep,   backword,cap_word,killword,pbeep,forword, pbeep,   
  185.     pbeep,   pbeep,   pbeep,   pbeep,   downcase_word, pbeep, pbeep, pbeep,
  186.     pbeep,   pbeep,   pbeep,   pbeep,   pbeep,   upcase_word,pbeep,  pbeep,
  187.     pbeep,   pbeep,   pbeep,   pbeep,   pbeep,   pbeep,   pbeep,   pbeep,
  188.     pbeep,   pbeep,   backword,cap_word,killword,pbeep,forword, pbeep,   
  189.     pbeep,   pbeep,   pbeep,   pbeep,   downcase_word, pbeep, pbeep, pbeep,
  190.     pbeep,   pbeep,   pbeep,   pbeep,   pbeep,   upcase_word,pbeep,  pbeep,
  191.     pbeep,   pbeep,   pbeep,   pbeep,   pbeep,   pbeep,   pbeep,   pbeep
  192. };
  193.  
  194. /* miscellaneous global declarations */
  195.  
  196. #if unix
  197. char cmcont = '\\';        /* continuation character (used by cfmact) */
  198. #else
  199. char cmcont = '-';        /* TOPS-20's continuation character */
  200. #endif
  201.  
  202. int *disp_forward_char();
  203.  
  204.  
  205.  
  206. /* cmpact
  207. ** 
  208. ** Purpose:
  209. **   Action routine for an ESCAPE character.  First, cmdflt is called
  210. **   to attempt to stuff a default string into the command line.  If
  211. **   that fails, cmcplt is called to attempt completion on the current
  212. **   input.  This is a deferred action, and always causes wakeup after
  213. **   success.
  214. **/
  215.  
  216.  
  217. int 
  218. cmpact(fdblist,brk,deferred)
  219. fdb *fdblist;
  220. char brk;
  221. int deferred;
  222. {
  223.   if (!deferred)
  224.     return(CMxDFR);            /* wait for deferred mode */
  225.  
  226.   if (cmcsb._cmflg & CM_CMT) {        /* if inside a comment, just beep */
  227.     cmputc(BELL,cmcsb._cmoj);        /* beep if they asked us to */
  228.     cmxflsh();
  229.     return(CMxOK);
  230.   }
  231.  
  232.   if (cmdflt(fdblist) == CMxOK) {    /* first try filling a default */
  233.     cmcsb._cmflg |= CM_PFE;        /* wants wakeup -activate noise words*/
  234.     return(CMxGO);            /* wakeup on success */
  235.   }
  236.   else
  237.     return(cmcplt(TRUE));        /* otherwise try full completion */
  238. }
  239.  
  240.  
  241. /* cmpact2
  242. ** 
  243. ** Purpose:
  244. **   Action routine for a TAB character.  We only do this if input is
  245. **   coming from a TTY.  This is so that we won't choke on tabs in 
  246. **   Take and indirect files.  First, cmdflt is called
  247. **   to attempt to stuff a default string into the command line.  If
  248. **   that fails, cmcplt is called to attempt completion on the current
  249. **   input.  This is a deferred action, and always causes wakeup after
  250. **   success.
  251. **/
  252.  
  253. int 
  254. cmpact2(fdblist,brk,deferred)
  255. fdb *fdblist;
  256. char brk;
  257. int deferred;
  258. {
  259.   if (!(cmcsb._cmflg & CM_ITTY)) {
  260.       cmsti1(brk,0);
  261.       return(CMxOK);
  262.   }
  263.   return(cmpact(fdblist,brk,deferred));
  264. }
  265.  
  266. /* pcmact
  267. **
  268. ** Purpose:
  269. **   Action to perform partial completion on the current input.
  270. **/
  271.  
  272. int
  273. pcmact(fdblist,brk,deferred)
  274. fdb *fdblist;
  275. char brk;
  276. int deferred;
  277. {
  278.   if (!deferred)
  279.     return(CMxDFR);            /* wait for deferred mode */
  280.  
  281.   if (cmcsb._cmflg & CM_CMT) {        /* if inside a comment, just beep */
  282.     cmputc(BELL,cmcsb._cmoj);        /* beep if they asked us to */
  283.     cmxflsh();
  284.     return(CMxOK);
  285.   }
  286.  
  287.   if (cmpdflt(fdblist) == CMxOK) {    /* first try filling a default */
  288.     return(CMxGO);            /* wakeup on success */
  289.   }
  290.   else
  291.     return(cmcplt(FALSE));        /* use standard utility */
  292. }
  293.  
  294. /* hlpact
  295. **
  296. ** Purpose:
  297. **   Action routine for a help request.
  298. **/
  299.  
  300. int 
  301. hlpact(fdblist,brk,deferred)
  302. fdb *fdblist;
  303. char brk;
  304. int deferred;
  305. {
  306.   if (!deferred)
  307.     return(CMxDFR);            /* wait for deferred mode */
  308.  
  309.   if (cmcsb._cmflg & CM_CMT) {        /* if inside a comment */
  310.     cmsti1(brk,0);
  311.     return(CMxOK);
  312.   }
  313.  
  314.   return(cmhelp(fdblist,cmcsb._cmbkc));    /* use std help utility */
  315. }
  316.  
  317. /* cfmact
  318. **
  319. ** Purpose:
  320. **   Action routine for a confirmation.  Stuff a newline, and set the
  321. **   CM_CFM flag in the CSB.  Also, a newline character is set into
  322. **   field _cmbkc in the CSB, to match the newline that got stuffed
  323. **   into the buffer.  If the confirmation character was formfeed,
  324. **   clear the screen.  If the confirmation character was carriage
  325. **   return or newline, and if there is a continuation character
  326. **   at the end of the unparsed input buffer, no action is taken,
  327. **   but a newline is stuffed with CC_SKP flag on, and the CC_CSK
  328. **   flag is added to the hyphen (to make it skip conditionally on
  329. **   the newline's presence).
  330. **/
  331.  
  332.  
  333. int
  334. cfmact(fdblist,brk,deferred)
  335. fdb *fdblist;
  336. char brk;
  337. int deferred;
  338. {
  339.   int ret;
  340.   int *end;                /* end of current input */
  341.  
  342.   if (!deferred)
  343.       return(CMxDFR);
  344.  
  345.   if (cmcsb._cminc > 0) {        /* is there unparsed input? */
  346.     end = cmcsb._cmcur - 1;        /* point to last char */
  347.     if ((*end & CC_QCH) == cmcont) {    /* last char continuation char? */
  348.                     /*  (fails if quoted) */
  349.       *end |= CC_CSK;            /* make it conditionally skipped */
  350.       ret = cmsti1(NEWLINE,CC_SKP);    /* and stuff a skipped newline */
  351.       return(ret);            /* no wakeup */
  352.     }
  353.   }
  354.  
  355.   if (cmcsb._cmflg & CM_CMT) {        /* if inside a comment */
  356.       cmcsb._cmflg &= ~CM_CMT;        /* then turn off the comment */
  357.   }
  358.       
  359.   if (cmcsb._cmflg2 & CM_IND) {
  360.       cmsti1(' ',0 );
  361.       return(CMxOK);
  362.   }
  363.  
  364.   go_from(cmcsb._cmcur, cmcsb._cmptr + cmcsb._cminc);
  365.   cmcsb._cmcur = cmcsb._cmptr + cmcsb._cminc;
  366.  
  367.   ret = cmsti1(NEWLINE,0);        /* stuff newline */
  368.   if (ret != CMxOK)
  369.     return(ret);            /* propagate problems */
  370.  
  371.   cmcsb._cmflg |= CM_CFM;        /* set confirmed flag */
  372.   cmcsb._cmbkc = NEWLINE;        /* and set confirming char */
  373.   if ((brk == FORMFEED) &&
  374.       (cmcsb._cmflg2 & CM_CRT) &&
  375.       !(cmcsb._cmflg & CM_NEC)
  376.      )
  377.     cmxcls();                       /* clear the screen for a formfeed */
  378.   remember();                /* add to cmdline history */
  379.   return(CMxGO);            /* now wake them up */
  380. }
  381.  
  382. /* delact
  383. **
  384. ** Purpose:
  385. **   Erase back to and including the last non-hidden character in the
  386. **   command buffer.  If erasing continues into the parsed region, a
  387. **   reparse is signalled.
  388. **/
  389.  
  390. int
  391. delact(fdblist,brk,deferred)
  392. fdb *fdblist;
  393. char brk;
  394. int deferred;
  395. {
  396.   int *cp;                /* for scanning the command buffer */
  397.   int eralen;                /* number of characters to erase */
  398.  
  399.   cp = cmcsb._cmcur;            /* point to end of buffer */
  400.   while (cp-- != cmcsb._cmbfp) {     /* loop over all the chars */
  401.     if ((*cp & CC_HID) == 0)
  402.       break;                /* found a non-hidden character */
  403.   }
  404.   cp++;                    /* point to last nonhidden char */
  405.  
  406.   if (cp != cmcsb._cmbfp)        /* if there are nonhidden chars */
  407.     cp--;                /* consume the last one */
  408.  
  409.   eralen = (cmcsb._cmcur - cp);        /* get # of chars erased */
  410.   if (eralen == 0) {
  411.     if (cmcsb._cmflg & CM_TTY)
  412.       cmputc(BELL,cmcsb._cmoj);    /* beep if nothing */
  413.     return(CMxOK);
  414.   }
  415.  
  416. #ifdef undef
  417.   if (cmcsb._cmflg2 & CM_CRT)
  418.     cmcsb._cmcol = cmxera(eralen,FALSE); /* erase the characters */
  419.   else if ((*cp & (CC_HID | CC_NEC)) == 0) { 
  420.     cmechx('\\');            /* give erase marker on hardcopy */
  421.     cmechx((char) (*cp) & CC_CHR);
  422.   }
  423. #endif
  424.   return(delcurrent(eralen));
  425. }
  426.  
  427. /* wrdact
  428. **
  429. ** Purpose:
  430. **   Erase the last word of command line input.  Words consist of letters
  431. **   and digits.  All other characters are delimiters.  This action erases
  432. **   the last nonhidden character in the input, and then continues erasing
  433. **   until it is about to erase a delimiter.
  434. **/
  435.  
  436. int
  437. wrdact(fdblist,brk,deferred)
  438. fdb *fdblist;
  439. char brk;
  440. int deferred;
  441. {
  442.   int *cp;                /* pointer to deletion site */
  443.   int cc;                /* character under examination */
  444.   char c;
  445.   int eralen;                /* # of chars erased */
  446.  
  447.   cp = cmcsb._cmcur;            /* point to end of buffer */
  448.   while (cp-- != cmcsb._cmbfp) {     /* loop over all the chars */
  449.     if ((*cp & CC_HID) == 0)
  450.       break;                /* found a non-hidden character */
  451.   }
  452.   cp++;                    /* point to last nonhidden char */
  453.  
  454.   if (cp != cmcsb._cmbfp)
  455.     cp--;                /* erase at least 1 nonhidden char */
  456.   while (cp-- != cmcsb._cmbfp) {    /* search for nonhidden delimiter */
  457.     c = (cc = *cp) & CC_CHR;        /* get next char */
  458.     if (((cc & CC_HID) == 0) &&        /* nonhidden? */
  459.         ((c < '0') ||            /* and not a letter or digit? */
  460.      ((c > '9') && (c < 'A')) ||
  461.      ((c > 'Z') && (c < 'a')) ||
  462.      (c > 'z')
  463.     )
  464.        )
  465.       break;                /* yup, stop looking */
  466.   }
  467.   cp++;                    /* point to char after break */
  468.  
  469.   eralen = (cmcsb._cmcur - cp);        /* get # of chars erased */
  470.   if (eralen == 0) {
  471.     if (cmcsb._cmflg & CM_TTY)
  472.       cmputc(BELL,cmcsb._cmoj);     /* beep if nothing */
  473.     return(CMxOK);
  474.   }
  475.  
  476. #ifdef undef
  477.   if (cmcsb._cmflg2 & CM_CRT)
  478.     cmcsb._cmcol = cmxera(eralen,FALSE); /* erase the characters */
  479.   else
  480.     cmechx('_');            /* print underscore on hardcopy */
  481. #endif
  482.   return(delcurrent(eralen));
  483. }
  484.  
  485.  
  486. /* begact
  487. **
  488. ** Purpose:
  489. **   Erase the entire command line, back to the last unhidden newline
  490. **   character.  If the last character is a newline, it is erased, and 
  491. **   the prior line is erased back to the previous newline.
  492. **   If parsed characters are deleted, a reparse is called for.
  493. **/
  494.  
  495. int
  496. begact(fdblist,brk,deferred)
  497. fdb *fdblist;
  498. char brk;
  499. int deferred;
  500. {
  501.   int *cp;                /* pointer to deletion site */
  502.   int cc;                /* character under examination */
  503.   char c;
  504.   int eralen;                /* # of chars erased */
  505.  
  506.   cp = cmcsb._cmptr + cmcsb._cminc;     /* point to end of buffer */
  507.   while (cp-- != cmcsb._cmbfp) {     /* loop over all the chars */
  508.     if ((*cp & CC_HID) == 0)
  509.       break;                /* found a non-hidden character */
  510.   }
  511.   cp++;                    /* point to last nonhidden char */
  512.  
  513.   if (cp != cmcsb._cmbfp)
  514.     cp--;                /* erase at least 1 nonhidden char */
  515.   while (cp-- != cmcsb._cmbfp) {    /* search for nonhidden newline */
  516.     c = (cc = *cp) & CC_CHR;        /* get next char */
  517.     if (((cc & CC_HID) == 0) && (c == NEWLINE)) /* nonhidden newline? */
  518.       break;                /* yup, stop looking */
  519.   }
  520.   cp++;                    /* point to char after break */
  521.  
  522.   eralen = (cmcsb._cmptr - cp) + cmcsb._cminc; /* get # of chars erased */
  523.  
  524. #ifdef undef
  525.   if (cmcsb._cmflg2 & CM_CRT)
  526.     cmcsb._cmcol = cmxera(eralen,TRUE); /* erase the characters */
  527.   else {
  528.     cmxputs("^U");            /* signal line kill on hardcopy */
  529.     cmxnl();                /* move to a new line */
  530.     if (cp == cmcsb._cmbfp)        /* killed prompt line? */
  531.       cmxputs(cmcsb._cmrty);        /* then reprompt */
  532.   }
  533. #endif
  534.   cmcsb._cmcur = goto_end_of_line();
  535.   return(delcurrent(eralen));
  536. }
  537.  
  538. /* fixact
  539. **
  540. ** Purpose:
  541. **   Refresh the display of the current line of text, back to the
  542. **   last unhidden newline character.  If there is no newline, refresh the
  543. **   prompt and all the current text.  If the last character in the
  544. **   buffer is a newline, the previous line is refreshed.
  545. **/
  546.  
  547. int
  548. fixact(fdblist,brk,deferred)
  549. fdb *fdblist;
  550. char brk;
  551. int deferred;
  552. {
  553.   int *cp1, *cp2, *cp;            /* pointers into buffer */
  554.  
  555.   cp = cp2 = cp1 = cmcsb._cmcur;    /* point to end of buffer */
  556.   while(cp1 > cmcsb._cmbfp && (*(cp1-1) & CC_CHR) != '\n') cp1--;
  557.   while((cp2 < cmcsb._cmptr + cmcsb._cminc) && (*cp2 & CC_CHR) != '\n') cp2++;
  558.   
  559.  
  560.   if (cmcsb._cmflg2 & CM_CRT) {
  561.       cmputc('\r', cmcsb._cmoj);
  562.       cmceol();
  563.   }
  564.   else {
  565.     cmxputs("^R");            /* signal line kill on hardcopy */
  566.     cmxnl();                /* move to a new line */
  567.   }
  568.   cmcsb._cmcol = 0;
  569.   if (cp1 == cmcsb._cmbfp) {        /* killed prompt line? */
  570.       cmxputs(cmcsb._cmrty);        /* then reprompt */
  571.   }
  572.   
  573.   cmcsb._cmcur = cp1;
  574.   cmcsb._cmcur = disp_forward_char(cp2 - cp1);
  575.   cmcsb._cmcur = go_backward_char(cp2 - cp);
  576.   return(CMxOK);
  577. }
  578.  
  579.  
  580.  
  581. /* hstact
  582. **
  583. ** Purpose:
  584. **   Action routine to reinstate the command buffer from a previous
  585. **   failed parse.  If the CM_DRT flag is off in the CSB, then the
  586. **   prior input text is still intact.  That text is redisplayed, and
  587. **   the CSB pointers are set so that all of the text is considered
  588. **   unparsed.  Then a no-wakeup return is made (a wakeup would probably
  589. **   just cause the same parse failure again).
  590. **/
  591.  
  592. int
  593. hstact(fdblist,brk,deferred)
  594. fdb *fdblist;
  595. char brk;
  596. int deferred;
  597. {
  598.   int *cp;                /* pointer into command buffer */
  599.   int count,i;                /* number of chars to reinstate */
  600.  
  601.   if (!deferred)
  602.       return(CMxDFR);
  603.   if (cmcsb._cmflg & CM_DRT || cmcsb._cminc > 0)
  604.     return(CMxOK);            /* nothing to do if buffer is dirty */
  605.   count = cmcsb._cmhst - cmcsb._cmbfp;    /* count buffered chars */
  606.   cp = cmcsb._cmbfp;            /* point to beginning of buffer */
  607.   for (i = 0; i < count; i++) {
  608.       if ((cp[i] & CC_CHR) == NEWLINE) {
  609.       count = i;
  610.       break;
  611.       }
  612.   }
  613.   cmcsb._cminc = count;            /* this many chars now to parse */
  614.   cmcsb._cmcnt -= count;        /* count their presence */
  615.   cmcsb._cmflg |= CM_DRT;        /* now the buffer is dirty */
  616.   cmcsb._cmcur = cmcsb._cmbfp + count;    /* point at end of line */
  617.   while (count-- > 0)             /* step through the buffer */
  618.     if (((*cp) & CC_NEC) == 0)        /* originally echoed? */
  619.       cmechx((char) (*cp++) & CC_CHR);    /* then echo it now */
  620.     else
  621.       cp++;                /* else just move on */
  622.   return(CMxOK);
  623. }
  624.  
  625.  
  626.  
  627. /* bsact
  628. **
  629. ** Purpose:
  630. **   Action routine for a backspace.  If the buffer is dirty, invoke the
  631. **   single character deletion action.  Otherwise, invoke the history
  632. **   action.
  633. **/
  634.  
  635. int
  636. bsact(fdblist,brk,deferred)
  637. fdb *fdblist;
  638. char brk;
  639. int deferred;
  640. {
  641.   if (cmcsb._cmflg & CM_DRT)        /* buffer dirty? */
  642.     return(delact(fdblist,brk,deferred)); /* delete one char */
  643.   else
  644.     return(hstact(fdblist,brk,deferred)); /* otherwise try history */
  645. }
  646.  
  647.  
  648. /* quoact
  649. **
  650. ** Purpose:
  651. **   Enter the next character into the buffer with its quote flag
  652. **   turned on, so it will be treated as a normal character regardless
  653. **   of any handling it would normally receive.
  654. **/
  655.  
  656. int
  657. quoact(fdblist,brk,deferred)
  658. fdb *fdblist;
  659. char brk;
  660. int deferred;
  661. {
  662.   int c;            /* quoted character */
  663.   int ret;            /* result code from input operation */
  664.   
  665.   ret = cmgetc(&c,cmcsb._cmij); /* get another character */
  666.   if (ret != CMxOK)
  667.     return(ret);        /* propagate problems */
  668.   ret = cmsti1(c,CC_QUO);    /* enter the charcter, quoted */
  669.   return(ret);            /* CMxOK normally -- no wakeup */
  670. }
  671.  
  672. #define MAXINDIRECTIONS 25
  673. struct indir_stack_ent {
  674.     FILE *oldij, *oldoj;
  675.     int (*olderr)();
  676. };
  677.  
  678. struct indir_stack {
  679.     struct indir_stack_ent data[MAXINDIRECTIONS];
  680.     int sptr;
  681. };
  682.  
  683. static struct indir_stack indstack;
  684.  
  685. ind_oldfds() {
  686.     static int first = TRUE;
  687.     if (first) {
  688.     indstack.sptr = -1;
  689.     first = FALSE;
  690.     }
  691.     if (indstack.sptr >= MAXINDIRECTIONS) {
  692.     cmerjmp(CMxSOF, NULL);
  693.     }
  694.     indstack.sptr++;
  695.     indstack.data[indstack.sptr].oldij = cmcsb._cmij;
  696.     indstack.data[indstack.sptr].oldoj = cmcsb._cmoj;
  697.     indstack.data[indstack.sptr].olderr = cmcsb._cmerh;
  698. }
  699.  
  700. cmindend() {
  701.     if (indstack.sptr < 0)  {
  702.     cmcsb._cmflg2 &= ~CM_IND;
  703.     cmerjmp(CMxSUF, NULL);
  704.     }
  705.     fclose(cmcsb._cmij);
  706.     if (cmcsb._cmoj) 
  707.     fclose(cmcsb._cmoj);
  708.     cmseti(indstack.data[indstack.sptr].oldij,
  709.        indstack.data[indstack.sptr].oldoj, cmcsb._cmej);
  710.     cmcsb._cmerh = indstack.data[indstack.sptr].olderr;
  711.     indstack.sptr--;
  712.     if (indstack.sptr < 0)
  713.     cmcsb._cmflg2 &= ~CM_IND;
  714. }
  715.  
  716. cminderr(code) int code; {
  717.     cmindend();                /* turn off indirection */
  718.     cmerjmp(code,NULL);            /* call old error handler */
  719. }
  720.  
  721.  
  722. int indiract(fdblist, brk, deferred, flags)
  723. fdb *fdblist;
  724. char brk;
  725. int deferred,flags;
  726. {
  727.   char c;            /* quoted character */
  728.   int ret;            /* result code from input operation */
  729.   FILE *f;
  730.   
  731.   static fdb filfdb = { _CMFIL, CM_SDH, NULL, NULL,
  732.                 "Filename for indirect file", NULL, NULL };
  733.   static fdb cfmfdb = { _CMCFM, 0, NULL, NULL, NULL, NULL, NULL };
  734.   static brktab chrbrk = {
  735.       {
  736.       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  737.       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  738.       },
  739.       {
  740.       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  741.       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  742.       },
  743.   };
  744.   static fdb chrfdb = { _CMCHAR, CM_SDH, NULL, NULL,
  745.                  "Filename for indirect file", NULL, &chrbrk };
  746.   static int entered = FALSE;
  747.   fdb *used;
  748.   pval pv;
  749.   static char *fname = NULL;
  750.   char *malloc();
  751.   int i;
  752.  
  753.   if (cmcsb._cmflg & CM_CMT) {        /* if inside a comment,  */
  754.       cmsti1(brk,0);            /* just insert the break char */
  755.       return(CMxOK);
  756.   }
  757.  
  758.   if (fname != NULL)            /* free up old filename */
  759.       free(fname);
  760.  
  761.   if (cmcsb._cmflg2 & CM_NIN) { /* no indirections allowed  */
  762.       cmsti1(brk,0);            /* just insert the break char */
  763.       return(CMxOK);            /* and go home */
  764.   }
  765.  
  766.   if (!deferred) {
  767.     return(CMxDFR);            /* wait for deferred mode */
  768.   }
  769.  
  770.   if (!(flags & CC_ACT))
  771.       cmsti1(brk,CC_ACT);            /* make it show up. */
  772.   cmcsb._cmflg &= ~CM_ACT;
  773.  
  774.   for(i = 0; i < 16; i++) {
  775.       chrbrk._br1st[i] = 0xff;
  776.       chrbrk._brrest[i] = 0xff;
  777.   }
  778.   chrbrk._br1st[brk/8] &= ~(1<<(7-(brk%8))); /* turn off the bit */
  779.   chrbrk._brrest[brk/8] &= ~(1<<(7-(brk%8))); /* turn off the bit */
  780.   parse(&chrfdb, &pv, &used);
  781.   parse(&filfdb, &pv, &used);        /* parse filename */
  782.   fname = malloc(strlen(pv._pvfil[0]) + 1); /* copy it */
  783.   strcpy(fname,pv._pvfil[0]);
  784.   parse(&cfmfdb, &pv, &used);        /* parse a confirm. */
  785.   
  786.   ind_oldfds();
  787.   f = fopen(fname,"r");
  788.   if (f == NULL) {
  789.       cmcsb._cmerr = 0;
  790.       indstack.sptr--;
  791.       cmerjmp(0, NULL);
  792.   }
  793.   cmseti(f,NULL,cmcsb._cmej);
  794.   cmcsb._cmerh = cminderr;
  795.   cmcsb._cmflg2 |= CM_IND;        /* turn on indirection flag */
  796.   return(CMxOK);
  797. }
  798.  
  799. #ifdef TIOCSUST
  800. int
  801. loadav(fdblist,brk,deferred)
  802. {
  803.     int x,y,z;
  804.     int ret;
  805.     int i;
  806.  
  807.     ioctl(fileno(cmcsb._cmij),TIOCGETD,&y); /* get line discipline */
  808.     ioctl(fileno(cmcsb._cmij),TIOCSETD,&x); /* set to new line discipline */
  809.     if (!ioctl(fileno(cmcsb._cmij),TIOCSUST,&x)) { /* show the load */
  810.     fixact(fdblist, brk, deferred);
  811.     }
  812.     ioctl(fileno(cmcsb._cmij),TIOCSETD,&y); /* restore line disc. */
  813.     return(CMxOK);            /* all done. */
  814. }
  815.  
  816. #endif /* TIOCSUST */
  817.  
  818.  
  819. /* 
  820.  * routines to implement command line history.
  821.  */
  822.  
  823.  
  824. /* 
  825.  * add a line to the command line history (if we have one).
  826.  */
  827. remember() {
  828.     cmhist *h = cmcsb._cmhist;
  829.     int i,len,j;
  830.     if (h == NULL) {
  831.     cmhst(10);
  832.     h = cmcsb._cmhist;
  833.     }
  834.     if (h->enabled == FALSE || h->len == 0)
  835.     return;
  836.     i =  h->next % h->len;
  837.     len = cmcsb._cmptr - cmcsb._cmbfp + cmcsb._cminc;
  838.     if (cmcsb._cmbfp[len-1] == '\n')
  839.     len--;
  840.     if (len == 0) return;
  841.     h->bufs[i].buf = (int *)cmrealloc(h->bufs[i].buf, len * sizeof(int));
  842.     for(j = 0; j < len; j++) {
  843.     h->bufs[i].buf[j] = cmcsb._cmbfp[j];
  844.     }
  845.     h->bufs[i].len = len;
  846.     h->next++;
  847.     h->next %= h->len;
  848.     h->current = h->next;
  849.     if (h->bufs[h->next].buf) {
  850.     free(h->bufs[h->next].buf);
  851.     h->bufs[h->next].buf = NULL;
  852.     h->bufs[h->next].len = 0;
  853.     }
  854. }
  855.  
  856. int 
  857. nextact(fdblist,brk,deferred)
  858. fdb *fdblist;
  859. char brk;
  860. int deferred;
  861. {
  862.     cmhist *h = cmcsb._cmhist;
  863.     int i;
  864.     int next;
  865.     if (h == NULL || h->len == 0) {
  866.     cmputc(BELL,cmcsb._cmoj);
  867.     cmxflsh();
  868.     return(CMxOK);
  869.     }
  870.     next = (h->current + h->len + 1) % h->len;
  871.     if (h->bufs[next].buf == NULL || h->next == h->current) {
  872.     cmputc(BELL,cmcsb._cmoj);
  873.     cmxflsh();
  874.     return(CMxOK);
  875.     }
  876.     h->current = next;
  877.     begact(fdblist,brk,deferred);
  878.     for( i= 0; i < h->bufs[next].len; i++)
  879.     cmsti1(h->bufs[next].buf[i] & CC_CHR, h->bufs[next].buf[i] & ~CC_CHR);
  880.     cmcsb._cmflg &= ~CM_DRT;
  881.     return(force_reparse());
  882. }
  883.  
  884.  
  885. int 
  886. prevact(fdblist,brk,deferred)
  887. fdb *fdblist;
  888. char brk;
  889. int deferred;
  890. {
  891.     cmhist *h = cmcsb._cmhist;
  892.     int i;
  893.     int prev;
  894.  
  895.     if (h == NULL || h->len == 0) {
  896.     cmputc(BELL,cmcsb._cmoj);
  897.     cmxflsh();
  898.     return(CMxOK);
  899.     }
  900.     prev = (h->current + h->len - 1) % h->len;
  901.  
  902.     if (h->bufs[prev].buf == NULL) {
  903.     cmputc(BELL,cmcsb._cmoj);
  904.     cmxflsh();
  905.     return(CMxOK);
  906.     }
  907.     h->current = prev;
  908.     cmcsb._cmcur = (int *)go_from(cmcsb._cmcur, cmcsb._cmptr + cmcsb._cminc);
  909.     delcurrent(cmcsb._cmcur - cmcsb._cmbfp);
  910.     for( i= 0; i < h->bufs[prev].len; i++)
  911.     cmsti1(h->bufs[prev].buf[i] & CC_CHR, h->bufs[prev].buf[i] & ~CC_CHR);
  912.     cmcsb._cmflg &= ~CM_DRT;
  913.     return(force_reparse());
  914. }
  915.  
  916.  
  917. int
  918. delcurrent(eralen)
  919. int eralen;
  920. {
  921.   int *p,*p1, i= 0;
  922.   int l,c,len;
  923.   int lines,col;
  924.  
  925.                     /* get to end of line */
  926.   p = cmcsb._cmptr + cmcsb._cminc;
  927.   relcharpos(&l, &c, cmcsb._cmcur-eralen, p); /* how far to go? */
  928.  
  929.   go_backward_char(eralen);        /* back up past stuff to be deleted */
  930.   lines = l;                /* how many lines to clear */
  931.   col = cmcsb._cmcol;            /* column to returtn to */
  932.  
  933.   bcopy(cmcsb._cmcur, cmcsb._cmcur-eralen, /* update the buffers */
  934.     (cmcsb._cmptr + cmcsb._cminc - cmcsb._cmcur)*sizeof(*cmcsb._cmbfp));
  935.   cmcsb._cmcnt += eralen;
  936.   cmcsb._cmcur -= eralen;
  937.   p -= eralen;
  938.  
  939.   cmceol();                /* clear to end of line */
  940.   for(p1 = cmcsb._cmcur; p1 < p; p1++) {
  941.     if (!(*p1 & (CC_NEC|CC_HID))) {
  942.       cmechx(*p1);
  943.       if (((*p1) & CC_CHR) == '\n') {
  944.     cmceol();
  945.     lines--;
  946.       }
  947.       else {
  948.     if (cmcsb._cmcol == 0)
  949.       lines--;
  950.       }
  951.     }
  952.   }
  953.   cmceol();
  954.   if (lines > 0) {
  955.     for(; lines > 0; lines--) {
  956.       cmxnl(cmcsb._cmoj);
  957.       cmceol();
  958.     }
  959.     cmxputc('\r',cmcsb._cmoj);
  960.     go_up_line(l);
  961.     go_forward(col);
  962.   }
  963.   else {
  964.     go_from(p, cmcsb._cmcur);
  965.   }
  966.   cmcsb._cmcol = col;
  967.  
  968.   if (cmcsb._cmcur <= cmcsb._cmptr) {    /* erased back to parsed data? */
  969.     cmcsb._cminc = cmcsb._cminc + cmcsb._cmptr - cmcsb._cmbfp - eralen;
  970.     cmcsb._cmptr = cmcsb._cmbfp;    /* yup, backup parsed pointer */
  971.     return(CMxRPT);            /* and call for reparse */
  972.   }
  973.   else {
  974.     cmcsb._cminc -= eralen;
  975.     return(CMxOK);
  976.   }
  977. }
  978.  
  979. int
  980. begline(fdblist,brk,deferred)
  981. fdb *fdblist;
  982. char brk;
  983. int deferred;
  984. {
  985.     cmcsb._cmcur = goto_beginning_of_line();
  986.     return(maybe_reparse());
  987. }
  988.  
  989. int
  990. endline(fdblist,brk,deferred)
  991. fdb *fdblist;
  992. char brk;
  993. int deferred;
  994. {
  995.     cmcsb._cmcur = goto_end_of_line();
  996.     return(maybe_reparse());
  997. }
  998.  
  999.  
  1000.  
  1001. int
  1002. backchar(fdblist,brk,deferred)
  1003. fdb *fdblist;
  1004. char brk;
  1005. int deferred;
  1006. {
  1007.     if (cmcsb._cmcur > cmcsb._cmbfp) {
  1008.     cmcsb._cmcur = go_backward_char(1);
  1009.     return(maybe_reparse());
  1010.     }
  1011.     else {
  1012.       cmputc(BELL,cmcsb._cmoj);    /* beep if nothing */
  1013.       return(CMxOK);
  1014.     }
  1015. }
  1016.  
  1017.  
  1018.  
  1019. int
  1020. forchar(fdblist,brk,deferred)
  1021. fdb *fdblist;
  1022. char brk;
  1023. int deferred;
  1024. {
  1025.     if (cmcsb._cmcur < cmcsb._cmptr + cmcsb._cminc) {
  1026.     cmcsb._cmcur = go_forward_char(1);
  1027.     cmcsb._cmflg &= ~CM_RPT;
  1028.     return(maybe_reparse());
  1029.     }
  1030.     else {
  1031.       cmputc(BELL,cmcsb._cmoj);    /* beep if nothing */
  1032.       return(CMxOK);
  1033.     }
  1034. }
  1035.  
  1036.  
  1037.  
  1038. int
  1039. delchar(fdblist,brk,deferred)
  1040. fdb *fdblist;
  1041. char brk;
  1042. int deferred;
  1043. {
  1044.     int *p,i=0;
  1045.     
  1046.     if (cmcsb._cmcur < cmcsb._cmptr + cmcsb._cminc) {
  1047.     cmcsb._cmcur = go_forward_char(1);
  1048.     return(delcurrent(1));        /* deletes backwards */
  1049.     }
  1050.     else {
  1051.       if (cmcsb._cmcur == cmcsb._cmbfp && /* empty line */
  1052.       cmcsb._cmcur == cmcsb._cmptr + cmcsb._cminc
  1053.       && !ignore_eof)
  1054.       return(CMxEOF);
  1055.       cmputc(BELL,cmcsb._cmoj);    /* beep if nothing */
  1056.       return(CMxOK);
  1057.     }
  1058. }
  1059.  
  1060.  
  1061.  
  1062. maybe_reparse()
  1063. {
  1064.   if (cmcsb._cmcur <= cmcsb._cmptr) {    /* erased back to parsed data? */
  1065.     return(force_reparse());
  1066.   }
  1067.   return(CMxOK);
  1068. }
  1069.  
  1070. force_reparse() 
  1071. {
  1072.     cmcsb._cminc = cmcsb._cminc + cmcsb._cmptr - cmcsb._cmbfp;
  1073.     cmcsb._cmptr = cmcsb._cmbfp;    /* yup, backup parsed pointer */
  1074.     return(CMxRPT);            /* and call for reparse */
  1075. }
  1076.  
  1077. int
  1078. killeol(fdblist,brk,deferred)
  1079. fdb *fdblist;
  1080. char brk;
  1081. int deferred;
  1082. {
  1083.     int *p = cmcsb._cmcur;
  1084.     cmcsb._cmcur = goto_end_of_line();
  1085.     delcurrent(cmcsb._cmcur - p);
  1086.     return(maybe_reparse());
  1087. }
  1088.  
  1089.  
  1090. #ifdef TIOCSUST
  1091. int
  1092. twiddle_or_load(fdblist,brk,deferred)
  1093. fdb *fdblist;
  1094. char brk;
  1095. int deferred;
  1096. {
  1097.     if (cmcsb._cmcur == cmcsb._cmbfp) 
  1098.     return(loadav(fdblist, brk, deferred));
  1099.     return(twiddle(fdblist, brk, deferred));
  1100. }
  1101. #endif
  1102.  
  1103.  
  1104. int
  1105. twiddle(fdblist,brk,deferred)
  1106. fdb *fdblist;
  1107. char brk;
  1108. int deferred;
  1109. {
  1110.     int tmp;
  1111.     int *cp;
  1112.  
  1113.     if (cmcsb._cmptr + cmcsb._cminc - cmcsb._cmbfp < 2) {
  1114.     cmputc(BELL,cmcsb._cmoj);    /* beep if nothing to twiddle */
  1115.     return(CMxOK);
  1116.     }
  1117.     if (cmcsb._cmcur == cmcsb._cmptr + cmcsb._cminc) { /* end of line? */
  1118.     cp = cmcsb._cmcur = go_backward_char(2);
  1119.     tmp = *cp;
  1120.     *cp = *(cp+1);
  1121.     *(cp+1) = tmp;
  1122.     cmcsb._cmcur = disp_forward_char(2);
  1123.     if (cmcsb._cminc < 2) {
  1124.         return(force_reparse());
  1125.     }
  1126.     return(CMxOK);
  1127.     }
  1128.     if (cmcsb._cmcur == cmcsb._cmbfp) {    /* beginning of line? */
  1129.     cp = cmcsb._cmcur;
  1130.     tmp = *cp;
  1131.     *cp = *(cp+1);
  1132.     *(cp+1) = tmp;
  1133.     cmcsb._cmcur = disp_forward_char(2);
  1134.     cmcsb._cmcur = go_backward_char(2);
  1135.     return(CMxOK);
  1136.     }
  1137.     cp = cmcsb._cmcur = go_backward_char(1);
  1138.     tmp = *cp;
  1139.     *cp = *(cp+1);
  1140.     *(cp+1) = tmp;
  1141.     cmcsb._cmcur = disp_forward_char(2);
  1142.     if (cmcsb._cminc < 2)
  1143.     return(force_reparse());
  1144.     return(maybe_reparse());
  1145. }
  1146.  
  1147. int
  1148. cmprefix(fdblist,brk,deferred)
  1149. fdb *fdblist;
  1150. char brk;
  1151. int deferred;
  1152. {
  1153.     int c;
  1154.     static int prebrk;
  1155.     int ret;
  1156.  
  1157.     cmcsb._cmflg &= ~CM_ACT;
  1158.     if (!deferred &&  !(cmcsb._cmflg & CM_ESC)) {
  1159.     c = cmgetc(&prebrk, cmcsb._cmij);
  1160.     if (c == CMxEOF)
  1161.         return(CMxEOF);
  1162.     }
  1163.     if (cmcsb._cmpract[prebrk] == NULL) {
  1164.     return(CMxPRE);
  1165.     }
  1166.     ret = (*cmcsb._cmpract[prebrk])(fdblist,prebrk,deferred);
  1167.     if (ret == CMxDFR) 
  1168.     cmcsb._cmflg |= CM_ESC;
  1169.     return(ret);
  1170. }
  1171.  
  1172.  
  1173.  
  1174. int
  1175. killword(fdblist,brk,deferred)
  1176. fdb *fdblist;
  1177. char brk;
  1178. int deferred;
  1179. {
  1180.     int i;
  1181.  
  1182.     for(i = 0; i < cmcsb._cmptr + cmcsb._cminc - cmcsb._cmcur; i++) {
  1183.     if (iswordchar(cmcsb._cmcur[i] & CC_CHR)) 
  1184.         break;
  1185.     }
  1186.     for(; i < cmcsb._cmptr + cmcsb._cminc - cmcsb._cmcur; i++) {
  1187.     if (!iswordchar(cmcsb._cmcur[i] & CC_CHR)) {
  1188.         break;
  1189.     }
  1190.     }
  1191.     cmcsb._cmcur = go_forward_char(i);
  1192.     return(delcurrent(i));
  1193. }
  1194.  
  1195.  
  1196. int
  1197. backword(fdblist,brk,deferred)
  1198. fdb *fdblist;
  1199. char brk;
  1200. int deferred;
  1201. {
  1202.     int *p;
  1203.  
  1204.     for(p = cmcsb._cmcur - 1 ; p >= cmcsb._cmbfp; p--) {
  1205.     if (iswordchar(*p & CC_CHR)) 
  1206.         break;
  1207.     }
  1208.     for(; p >= cmcsb._cmbfp; p--) {
  1209.     if (!iswordchar(*p & CC_CHR)) {
  1210.         p++;
  1211.         break;
  1212.     }
  1213.     }
  1214.     if (p < cmcsb._cmbfp) p = cmcsb._cmbfp;
  1215.     cmcsb._cmcur = go_backward_char(cmcsb._cmcur-p);
  1216.     return(maybe_reparse());
  1217. }
  1218.  
  1219.  
  1220. int
  1221. forword(fdblist,brk,deferred)
  1222. fdb *fdblist;
  1223. char brk;
  1224. int deferred;
  1225. {
  1226.     int i;
  1227.  
  1228.     for(i = 0; i < cmcsb._cmptr + cmcsb._cminc - cmcsb._cmcur; i++) {
  1229.     if (iswordchar(cmcsb._cmcur[i] & CC_CHR)) 
  1230.         break;
  1231.     }
  1232.     for(; i < cmcsb._cmptr + cmcsb._cminc - cmcsb._cmcur; i++) {
  1233.     if (!iswordchar(cmcsb._cmcur[i] & CC_CHR)) {
  1234.         break;
  1235.     }
  1236.     }
  1237.     cmcsb._cmcur = go_forward_char(i);
  1238.     return(CMxOK);
  1239. }
  1240.  
  1241. int
  1242. cmp_pre(fdblist,brk,deferred)
  1243. fdb *fdblist;
  1244. char brk;
  1245. int deferred;
  1246. {
  1247.     if (cmcsb._cmcur == cmcsb._cmptr + cmcsb._cminc) {
  1248.     return(cmpact(fdblist, brk, deferred));
  1249.     }
  1250.     else {
  1251.     return(cmprefix(fdblist, brk, deferred));
  1252.     }
  1253. }
  1254.  
  1255. int
  1256. pbeep(fdblist, brk, deferred)
  1257. fdb *fdblist;
  1258. char brk;
  1259. int deferred;
  1260. {
  1261.     cmputc(BELL,cmcsb._cmoj);        /* beep */
  1262.     return(CMxOK);
  1263. }
  1264.  
  1265. iswordchar(c)
  1266. char c;
  1267. {
  1268.     return(isalnum(c) || c == '.' || c == '_' || c == '-');
  1269. }
  1270.  
  1271.  
  1272.  
  1273.  
  1274. /*
  1275.  *  case changing 
  1276.  */
  1277. int
  1278. upcase_word(fdblist, brk, deferred)
  1279. fdb *fdblist;
  1280. char brk;
  1281. int deferred;
  1282. {
  1283.     if (forward_casing)
  1284.     return(fupcase_word(fdblist, brk, deferred));
  1285.     else
  1286.     return(bupcase_word(fdblist, brk, deferred));
  1287. }
  1288.  
  1289. int
  1290. downcase_word(fdblist, brk, deferred)
  1291. fdb *fdblist;
  1292. char brk;
  1293. int deferred;
  1294. {
  1295.     if (forward_casing)
  1296.     return(fdowncase_word(fdblist, brk, deferred));
  1297.     else
  1298.     return(bdowncase_word(fdblist, brk, deferred));
  1299. }
  1300.  
  1301. int
  1302. cap_word(fdblist, brk, deferred)
  1303. fdb *fdblist;
  1304. char brk;
  1305. int deferred;
  1306. {
  1307.     if (forward_casing)
  1308.     return(fcap_word(fdblist, brk, deferred));
  1309.     else
  1310.     return(bcap_word(fdblist, brk, deferred));
  1311. }
  1312.  
  1313. /*
  1314.  * backward case changing
  1315.  */
  1316.  
  1317. int
  1318. bupcase_word(fdblist, brk, deferred)
  1319. fdb *fdblist;
  1320. char brk;
  1321. int deferred;
  1322. {
  1323.     return(bcase_word(fdblist, brk, deferred, 'U'));
  1324. }
  1325.  
  1326. int
  1327. bdowncase_word(fdblist, brk, deferred)
  1328. fdb *fdblist;
  1329. char brk;
  1330. int deferred;
  1331. {
  1332.     return(bcase_word(fdblist, brk, deferred, 'D'));
  1333. }
  1334.  
  1335. int
  1336. bcap_word(fdblist, brk, deferred)
  1337. fdb *fdblist;
  1338. char brk;
  1339. int deferred;
  1340. {
  1341.     return(bcase_word(fdblist, brk, deferred, 'C'));
  1342. }
  1343.  
  1344. int
  1345. bcase_word(fdblist, brk, deferred, action)
  1346. fdb *fdblist;
  1347. char brk;
  1348. int deferred;
  1349. int action;
  1350. {
  1351.     int *cp = cmcsb._cmcur;
  1352.     int *p,*bp;
  1353.  
  1354.     for(p = cmcsb._cmcur - 1 ; p >= cmcsb._cmbfp; p--) { /* skip whitespace */
  1355.     if (iswordchar(*p & CC_CHR)) 
  1356.         break;
  1357.     }
  1358.     for(; p >= cmcsb._cmbfp; p--) {
  1359.     if (!iswordchar(*p & CC_CHR)) {
  1360.         p++;
  1361.         break;
  1362.     }
  1363.     }
  1364.     if (p < cmcsb._cmbfp) p = cmcsb._cmbfp;
  1365.     cmcsb._cmcur = go_backward_char(cp - p); /* back up */
  1366.     for(bp = p; bp < cp; bp++) {
  1367.     switch(action) {
  1368.     case 'C':
  1369.         if (bp == p) {
  1370.         if (islower(*bp)) {
  1371.             *bp = (*bp & 0xff80) | toupper(*bp & CC_CHR);
  1372.         }
  1373.         }
  1374.         else if (isupper(*bp)) {
  1375.         *bp = (*bp & 0xff80) | tolower(*bp & CC_CHR);
  1376.         }
  1377.         break;
  1378.     case 'U':
  1379.         if (islower(*bp)) {
  1380.         *bp = (*bp & 0xff80) | toupper(*bp & CC_CHR);
  1381.         }
  1382.         break;
  1383.     case 'D':
  1384.         if (isupper(*bp)) {
  1385.         *bp = (*bp & 0xff80) | tolower(*bp & CC_CHR);
  1386.         }
  1387.         break;
  1388.     }
  1389.     }
  1390.  
  1391.     cmcsb._cmcur = disp_forward_char(cp - p);
  1392.     if (p < cmcsb._cmptr)
  1393.     return(CMxRPT);
  1394.     return(CMxOK);
  1395. }
  1396.  
  1397. /*
  1398.  * forward case changing
  1399.  */
  1400. int
  1401. fupcase_word(fdblist, brk, deferred)
  1402. fdb *fdblist;
  1403. char brk;
  1404. int deferred;
  1405. {
  1406.     return(fcase_word(fdblist, brk, deferred, 'U'));
  1407. }
  1408.  
  1409. int
  1410. fdowncase_word(fdblist, brk, deferred)
  1411. fdb *fdblist;
  1412. char brk;
  1413. int deferred;
  1414. {
  1415.     return(fcase_word(fdblist, brk, deferred, 'D'));
  1416. }
  1417.  
  1418. int
  1419. fcap_word(fdblist, brk, deferred)
  1420. fdb *fdblist;
  1421. char brk;
  1422. int deferred;
  1423. {
  1424.     return(fcase_word(fdblist, brk, deferred, 'C'));
  1425. }
  1426.  
  1427.  
  1428. int
  1429. fcase_word(fdblist, brk, deferred, action)
  1430. fdb *fdblist;
  1431. char brk;
  1432. int deferred;
  1433. int action;
  1434. {
  1435.     int *cp = cmcsb._cmcur;
  1436.     int *p,*bp;
  1437.     int *wp = cp;
  1438.  
  1439.                     /* skip whitespace */
  1440.     for(p = cmcsb._cmcur ; p < cmcsb._cmptr + cmcsb._cminc; p++) {
  1441.     if (iswordchar(*p & CC_CHR)) 
  1442.         break;
  1443.     }
  1444.     wp = p;
  1445.     for(; p < cmcsb._cmptr + cmcsb._cminc; p++) {
  1446.     if (!iswordchar(*p & CC_CHR)) {
  1447.         break;
  1448.     }
  1449.     }
  1450.     for(bp = cp; bp < p; bp++) {
  1451.     switch(action) {
  1452.     case 'C':
  1453.         if (bp == wp) {
  1454.         if (islower(*bp)) {
  1455.             *bp = (*bp & 0xff80) | toupper(*bp & CC_CHR);
  1456.         }
  1457.         }
  1458.         else if (isupper(*bp)) {
  1459.         *bp = (*bp & 0xff80) | tolower(*bp & CC_CHR);
  1460.         }
  1461.         break;
  1462.     case 'U':
  1463.         if (islower(*bp)) {
  1464.         *bp = (*bp & 0xff80) | toupper(*bp & CC_CHR);
  1465.         }
  1466.         break;
  1467.     case 'D':
  1468.         if (isupper(*bp)) {
  1469.         *bp = (*bp & 0xff80) | tolower(*bp & CC_CHR);
  1470.         }
  1471.         break;
  1472.     }
  1473.     }
  1474.     cmcsb._cmcur = disp_forward_char(p - cp);
  1475.     if (cmcsb._cmcur > cmcsb._cmptr + cmcsb._cminc)
  1476.     cmcsb._cmcur = cmcsb._cmptr + cmcsb._cminc;
  1477.     return(CMxOK);
  1478. }
  1479.  
  1480. /*
  1481.  * install a builtin action table
  1482.  * accepts a flagword containing the types to install.
  1483.  * see also cmsetact
  1484.  */
  1485. cmbuiltin_act(actiontype)
  1486. int actiontype;
  1487. {
  1488.     switch (actiontype & 0x000f) {
  1489.     case CMaNOSET:            /* not specified in this flagword */
  1490.     break;
  1491.     case CMaEMACS:
  1492.     cmsetact(emacs_actions, cmcsb._cmact);
  1493.     cmsetact(emacs_prefix_actions, cmcsb._cmpract);
  1494.     break;
  1495.     case CMaGMACS:
  1496.     cmsetact(gmacs_actions, cmcsb._cmact);
  1497.     cmsetact(emacs_prefix_actions, cmcsb._cmpract);
  1498.     break;
  1499.     case CMaVI:
  1500.     fprintf(stderr,"?VI command line editting is not implemented\n");
  1501.     break;
  1502.     default:
  1503.     fprintf(stderr,"?Invalid Command line editor specified\n");
  1504.     break;
  1505.     }
  1506.     if (actiontype & CMaBCASE)
  1507.     forward_casing = FALSE;
  1508.     if (actiontype & CMaFCASE)
  1509.     forward_casing = TRUE;
  1510.     if (actiontype & CMaEOF)
  1511.     ignore_eof = FALSE;
  1512.     if (actiontype & CMaIEOF)
  1513.     ignore_eof = TRUE;
  1514. }
  1515.  
  1516. /*
  1517.  * install an action table in a CSB action vector
  1518.  */
  1519. cmsetact(acttab, actvec)
  1520. cmacttab *acttab;
  1521. int (*(actvec[NCHAR]))();
  1522. {
  1523.     cmacttab *a;
  1524.  
  1525.     bzero(actvec, sizeof(NCHAR * sizeof(*actvec)));
  1526.     for(a = acttab; a->actionchar && a->actionfunc; a++)
  1527.     actvec[a->actionchar] = a->actionfunc;
  1528. }
  1529.  
  1530.  
  1531. /*
  1532.  * handle action related CCMD environment variables
  1533.  */
  1534. cm_env_actions(env)
  1535. char *env;
  1536. {
  1537.     char *cp=env, *cp1, *index();
  1538.     int flags=0;
  1539.     
  1540.     while(cp) {
  1541.     cp1 = index(cp, ':');
  1542.     if (cp1)
  1543.         *cp1 = '\0';
  1544.     flags |= cm_env_var(cp);
  1545.     if (cp1) 
  1546.         *cp1++ = ':';
  1547.     cp = cp1;
  1548.     }
  1549.     cmbuiltin_act(flags);
  1550. }
  1551.  
  1552. /*
  1553.  * interpret a ccmd environment variable (if possible)
  1554.  */
  1555.  
  1556. static struct {
  1557.     char *varname;
  1558.     int  value;
  1559. } envvars[] = {
  1560.     { "emacs", CMaEMACS },        /* emacs cmd line editing */
  1561.     { "gmacs", CMaGMACS },        /* gnuemac "   "     " */
  1562.     { "vi",    CMaVI },            /* vi      "   "     " */
  1563.     { "fcase", CMaFCASE },        /* forward up/downcasing */
  1564.     { "bcase", CMaBCASE },        /* backward up/downcasing */
  1565.     { "ignoreeof", CMaIEOF },        /* ignore eof */
  1566.     { "noignoreeof", CMaEOF },        /* return eof */
  1567.     { NULL, 0 }
  1568. };
  1569.  
  1570. static
  1571. cm_env_var(var)
  1572. char *var;
  1573. {
  1574.     int i;
  1575.  
  1576.     for(i = 0; envvars[i].varname; i++)
  1577.     if (ustrcmp(var, envvars[i].varname) == 0)
  1578.         return(envvars[i].value);
  1579.     return(0);
  1580. }
  1581.  
  1582.  
  1583.